#include <stdafx.h>

// Constants
// Less than
#define LT                         -1 
// Equal to
#define EQ                          0  
// Greater than
#define GT                          1

// Number of rule sets in each group 
#define DM_RULE_ANYWHERE_LAST_SET   4
#define DM_RULE_BEGINNING_LAST_SET  6
#define DM_RULE_ENDING_LAST_SET     6

// 64 entries max in the queue
#define QUEUE_MAX_LENGTH            64

// This is the Daitch-Mokotoff Rule Class.  Each instance represents a rule for
// converting an n-gram to a phonetic code in the D-M system
class DM_Rule {
public:
	BYTE nGramLength; // Length of an n-gram
	BYTE nGram[8]; // n-gram text
	BYTE Code1; // Primary Code 1
	BYTE Code2; // Alternate Code 2
	
	// Constructors
	DM_Rule(int rulenum, int len, const char *text, int c1, int c2) {
		this->nGramLength = len;
		memset(this->nGram, '\0', 8);
		memcpy (this->nGram, text, len);
		this->Code1 = c1;
		this->Code2 = c2;
	}

	DM_Rule(int rulenum, int len, const char *text, int c1) {
		this->nGramLength = len;
		memset(this->nGram, '\0', 8);
		memcpy (this->nGram, text, len);
		this->Code1 = this->Code2 = c1;
	}

	DM_Rule() {
		this->nGramLength = 0;
		memset(this->nGram, '\0', 8);
		this->Code1 = this->Code2 = 255;
	}
};

// Upper and lower boundaries for rule sets
class DM_Rule_Bounds {
public:
	int Lower;  // Lower rule set boundary
	int Upper;  // Upper rule set boundary

	// Constructor
	DM_Rule_Bounds(int l, int u) {
		this->Lower = l;
		this->Upper = u;
	}
};

// The RuleQueue class represents a queue of rules during processing
class RuleQueue {
private:
	// Read, write and QueueArray are the private properties of this class
	int     read;
	int     write;
	DM_Rule QueueArray[QUEUE_MAX_LENGTH];
public:
	void     EnQueue(DM_Rule *rule); // Adds a rule to the tail of the queue
	DM_Rule  DeQueue(); // Removes a rule from the front of the queue (FIFO order)
	bool     ItemsLeft(); // Are there any items left in the queue?

	// Constructor initializes the read and write pointers for the queue
	RuleQueue() {
		read = 0;
		write = 0;
	}
};
//Class for converting names to D-M encodings
class DM_Soundex {
private:
	// The Rules and associated arrays are declared as static for speed.  We should
	// only have to initialize all these rules once
	static DM_Rule         DM_Rule_Anywhere[170];
	static DM_Rule_Bounds  DM_Rule_Anywhere_Bounds[5];
	static DM_Rule         DM_Rule_Beginning[197];
	static DM_Rule_Bounds  DM_Rule_Beginning_Bounds[7];
	static DM_Rule         DM_Rule_Ending[55];
	static DM_Rule_Bounds  DM_Rule_Ending_Bounds[7];

	// Private methods
	// CompareNGram compares an ngram to a substring of a name.  It returns one of the
	// constants LT, EQ or GT
    static int CompareNGram(int startpos, BYTE *ngram, BYTE *name, int length);
	// Clean string removes all punctuation from a name and capitalizes it
	static void CleanString(BYTE *name, int &length);
	// AddQueue adds a rule to the rule queue
	//static void AddQueue(DM_Rule *rule);
	// Our Binary Seach routines to check the beginning, ending and 'anywhere else'
	// portions of the name for matching n-gram rules
	static DM_Rule CheckBeginning(BYTE *name, int &start, int finish);
	static DM_Rule CheckAnywhere(BYTE *name, int &start, int &finish);
	static DM_Rule CheckEnding(BYTE *name, int &start, int &finish);
	void InitEncodings(); // Initializes ecodings table
	int ApplyRules(RuleQueue &q); // Applies queued rules to the encodings table
	void QueueRules(BYTE *name, int &length, RuleQueue &q); // Queues rules from a name
	void SplitEncodings(int &count); // Splits (doubles) the encodings table size
	// Appends code to an encoding in the encodings table	
	void AppendCode(BYTE *encoding, BYTE length, BYTE code); 
	// Marks all duplicate entries in the encodings table
	void MarkDupes(int count);
public:
    BYTE DM_Encodings[512]; // DM_Encodings is a BYTE array that contains all the 
							// encodings in 8 bytes each.  The first 6 bytes are the
							// actual encoded value as ASCII chars; the 7th byte is 
							// a '\0' terminator and the 8th byte represents the length
							// of the encoding (used during processing)
	int Encode(BYTE *name, int &length); // The Encode method takes a name and length
										 // and populates the DM_Encodings table with
										 // the appropriate D-M Encodings
};

